package com.guozcc.bootweb.api.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.guozcc.bootweb.api.bean.User;
import com.guozcc.bootweb.api.component.ApiDemoComponent;
import com.guozcc.bootweb.api.mapper.UserMapper;
import com.guozcc.bootweb.platform.annotation.Trade;
import com.guozcc.bootweb.platform.annotation.Lock;
import com.guozcc.bootweb.platform.tools.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/api/")
public class ApiDemoController {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ApiDemoComponent apiDemoComponent;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private RedissonClient redissonClient;
    @Resource(name="commonThreadPoolTaskExecutor")//指定使用哪个线程池
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Trade(tradeCode="A403B001",tradeName="mybatis测试")
    public JSONObject a403B001(@RequestBody(required = false) JSONObject requestMessage) throws Exception {

        List<User> userList = apiDemoComponent.testTransactional("郭子超");


        return new JSONObject()
                .fluentPut("userlist",userList)
                .fluentPut("ec","success")
                .fluentPut("em","执行成功");
    }

    @Trade(tradeCode="A403B002",tradeName="异步测试")
    public JSONObject a403B002(@RequestBody(required = false) JSONObject requestMessage) throws Exception {
        log.info("执行主方法逻辑开始");
        apiDemoComponent.testAsynTask();
        log.info("执行主方法逻辑结束");


        return requestMessage.fluentPut("ec","success").fluentPut("em","请求已受理");
    }


    @Trade(tradeCode="A403B003",tradeName="redis测试")
    public JSONObject a403B003(@RequestBody(required = false) JSONObject requestMessage) throws Exception {
            // redisTemplate 操作不同的数据类型，api和我们的指令是一样的
                // opsForValue 操作字符串 类似String
                // opsForList  操作List 类似List
                // opsForSet
                // opsForHash
                // opsForZSet
                // opsForGeo
                // opsForHyperLogLog

        //      除了进本的操作，我们常用的方法都可以直接通过redisTemplate操作，比如事务，和基本的CRUD
        //    // 获取redis的连接对象
        //    //    RedisConnection connection =
        //        redisTemplate.getConnectionFactory().getConnection();
        //    //    connection.flushDb();
        //    //    connection.flushAll();
        //    redisTemplate.opsForValue().set("mykey","关注狂神说公众号");
        //    System.out.println(redisTemplate.opsForValue().get("mykey"));

        /**
         * hash
         */
        redisUtils.hmSet("myhash","hashkey1","hashvalue1");
        redisUtils.hmSet("myhash","hashkey2","hashvalue2");
        redisUtils.hmSet("myhash","hashkey3","hashvalue3");
        redisUtils.hmSet("myhash","hashkey1","hashvalue100");
        redisTemplate.expire("myhash",10, TimeUnit.SECONDS);
        Map<String, String> myhash = redisUtils.hashMapGet("myhash");


        /**
         * String
         */
        redisUtils.set("Login:custid","010415");
        final String s = redisUtils.get("Login:custid");
        Set<String> keys = redisUtils.keys("Login:cust*");
        return requestMessage.fluentPut("ec","success")
                .fluentPut("em","redis success")
                .fluentPut("myhash",myhash)
                .fluentPut("hashkey1",redisUtils.hmGet("myhash","hashkey1"));
    }


    @Trade(tradeCode="A403B004",tradeName="Redisson分布式锁(手动)")
    public JSONObject a403B004(@RequestBody(required = false) JSONObject requestMessage) throws Exception {

        RLock redissonLock = redissonClient.getLock("lockName");
        try {
            // 加锁，拿不到锁会一直自旋等待
            //redisson加的锁默认过期时长是30s,每10s续一次
            //redisson不会死锁，因为有过期时间
            log.info("加锁前");
            redissonLock.lock();
            log.info("加锁后");
            //业务逻辑。。。。。。。。。。

        }catch (Exception e){
            log.error("",e);
        }finally {
            log.info("解锁前");
            redissonLock.unlock();
            log.info("解锁后");
        }
        return requestMessage.fluentPut("ec","success")
                .fluentPut("em","redis success");
    }

    @Trade(tradeCode="A403B005",tradeName="Redisson分布式锁(注解)")
    @Lock(lockName = "username")
    public JSONObject a403B005(@RequestBody(required = false) JSONObject requestMessage) throws Exception {

        log.info("执行业务逻辑");

        return requestMessage.fluentPut("ec","success")
                .fluentPut("em","redis success");
    }

    @Trade(tradeCode="A403B006",tradeName="SpringBoot缓存测试 @Cacheable")
    public JSONObject a403B006(@RequestBody(required = false) JSONObject requestMessage) throws Exception {
        List<User> userList = apiDemoComponent.getUserListByUserName(requestMessage.getString("username"));
        return new JSONObject()
                .fluentPut("userlist",userList)
                .fluentPut("ec","success")
                .fluentPut("em","执行成功");
    }

    @Trade(tradeCode="A403B007",tradeName="SpringBoot缓存测试 @CachePut")
    public JSONObject a403B007(@RequestBody(required = false) JSONObject requestMessage) throws Exception {
        User user = new User();
        user.setUserid(1);
        user.setUsername(requestMessage.getString("username"));
        user.setAge(32);
        user.setSex("女");
        List<User> userList = apiDemoComponent.updateUser(user);
        return new JSONObject()
                .fluentPut("userlist",userList)
                .fluentPut("ec","success")
                .fluentPut("em","执行成功");
    }

    @Trade(tradeCode="A403B008",tradeName="SpringBoot缓存测试 @CacheEvict")
    public JSONObject a403B008(@RequestBody(required = false) JSONObject requestMessage) throws Exception {
        apiDemoComponent.deleteUserById(new User(){{
            setUserid(1);
            setUsername(requestMessage.getString("username"));
            setAge(32);
            setSex("女");
        }});
        return new JSONObject()
                .fluentPut("ec","success")
                .fluentPut("em","执行成功");
    }


    @Trade(tradeCode="A403B009",tradeName="线程池的使用")
    public JSONObject a403B009(@RequestBody(required = false) JSONObject requestMessage) throws Exception {

        JSONObject res = new JSONObject();

        CompletableFuture<Void> firstTask = CompletableFuture.runAsync(()->{
            log.info("firstTask");
            res.put("firstTask","执行firstTask");
        },threadPoolTaskExecutor);

        CompletableFuture<Void> secondTask = CompletableFuture.runAsync(()->{
            log.info("secondTask");
            res.put("secondTask","执行secondTask");
        },threadPoolTaskExecutor);



        CompletableFuture.allOf(firstTask,secondTask).get();

        log.info(res.toJSONString());
        return res
                .fluentPut("ec","success")
                .fluentPut("em","执行成功");
    }





















    //  car/2/owner/zhangsan
    @GetMapping("/car/{id}/owner/{username}")
    public Map<String,Object> getCar(@PathVariable("id") Integer id,
                                     @PathVariable("username") String name,
                                     @PathVariable Map<String,String> pv,
                                     @RequestHeader("User-Agent") String userAgent,
                                     @RequestHeader Map<String,String> header,
                                     @RequestParam("age") Integer age,
                                     @RequestParam("inters") List<String> inters,
                                     @RequestParam Map<String,String> params,
                                     @CookieValue("_ga") String _ga,
                                     @CookieValue("_ga") Cookie cookie){


        Map<String,Object> map = new HashMap<>();

//        map.put("id",id);
//        map.put("name",name);
//        map.put("pv",pv);
//        map.put("userAgent",userAgent);
//        map.put("headers",header);
        map.put("age",age);
        map.put("inters",inters);
        map.put("params",params);
        map.put("_ga",_ga);
        System.out.println(cookie.getName()+"===>"+cookie.getValue());
        return map;
    }


    @PostMapping("/save")
    public Map postMethod(@RequestBody String content){
        Map<String,Object> map = new HashMap<>();
        map.put("content",content);
        return map;
    }


    //1、语法： 请求路径：/cars/sell;low=34;brand=byd,audi,yd
    //2、SpringBoot默认是禁用了矩阵变量的功能
    //      手动开启：原理。对于路径的处理。UrlPathHelper进行解析。
    //              removeSemicolonContent（移除分号内容）支持矩阵变量的
    //3、矩阵变量必须有url路径变量才能被解析
    @GetMapping("/cars/{path}")
    public Map carsSell(@MatrixVariable("low") Integer low,
                        @MatrixVariable("brand") List<String> brand,
                        @PathVariable("path") String path){
        Map<String,Object> map = new HashMap<>();

        map.put("low",low);
        map.put("brand",brand);
        map.put("path",path);
        return map;
    }

    // /boss/1;age=20/2;age=10

    @GetMapping("/boss/{bossId}/{empId}")
    public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
                    @MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
        Map<String,Object> map = new HashMap<>();

        map.put("bossAge",bossAge);
        map.put("empAge",empAge);
        return map;

    }

    public static void main(String[] args) {
//生成的文件名字
        String fileName = "Student.xlsx";

        //创建一个列表使用列表来装我们要写入的数据。
        List<Student> Students = new ArrayList<>();

        //使用之前写的类实列化出我们的对象
        Student s1 = new Student("1001", "周星星", "男", 122);
        Student s2 = new Student("1002", "吴孟达", "男", 252);
        Student s3 = new Student("1003", "林青霞", "女", 225);
        Student s4 = new Student("1004", "彭于晏", "男", 229);

        //将数据添加进我们的列表中
        Students.add(s1);
        Students.add(s2);
        Students.add(s3);
        Students.add(s4);

        //使用EasyExcel提供的方法写入excel。
        //write方法里的两个参数是 文件名 和 模板类。
        //sheet方法里面对参数是excel表格下面的标签名。
        //doWrite方法的参数是 要写入的数据
        EasyExcel.write("D://"+fileName, Student.class).sheet("学生表").doWrite(Students);

    }
}
